using System;
using System.IO;
using System.Text;
using System.Xml;

namespace Td.Additional.Xml
{
    /// <summary>
    /// Removes the Xml Declaration and the XSD and XSI namespaces during writing
    /// Based on http://www.hanselman.com/blog/XmlFragmentWriterOmitingTheXmlDeclarationAndTheXSDAndXSINamespaces.aspx
    /// </summary>
    public class XmlFragmentWriter : XmlTextWriter
    {
        #region Private fields

        /// <summary>
        /// If set to true, the current xml tag will not be written
        /// </summary>
        private bool _skip = false;

        #endregion

        #region Static properties

        /// <summary>
        /// Defaul tbuffer size
        /// </summary>
        public static int DefaultBufferSize = 8192;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="XmlFragmentWriter"/> class.
        /// </summary>
        public XmlFragmentWriter()
            : base(new MemoryStream(DefaultBufferSize), Encoding.UTF8)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="XmlFragmentWriter"/> class.
        /// </summary>
        /// <param name="w">Der TextWriter, in den geschrieben werden soll. Hierbei wird vorausgesetzt, dass der TextWriter bereits auf die korrekte Codierung eingestellt ist.</param>
        public XmlFragmentWriter(TextWriter w)
            : base(w)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="XmlFragmentWriter"/> class.
        /// </summary>
        /// <param name="w">The w.</param>
        /// <param name="encoding">The encoding.</param>
        public XmlFragmentWriter(Stream w, Encoding encoding)
            : base(w, encoding)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="XmlFragmentWriter"/> class.
        /// </summary>
        /// <param name="filename">The filename.</param>
        /// <param name="encoding">The encoding.</param>
        public XmlFragmentWriter(string filename, Encoding encoding)
            : base(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None), encoding)
        {
        }

        #endregion

        #region Overriden attribute methods

        /// <summary>
        /// Gets the XML fragment in string format.
        /// </summary>
        public override String ToString()
        {
            return System.Text.Encoding.UTF8.GetString(((MemoryStream)BaseStream).ToArray());
        }

        /// <summary>
        /// Writes the start attribute.
        /// </summary>
        /// <param name="prefix">The prefix.</param>
        /// <param name="localName">Name of the local.</param>
        /// <param name="ns">The namespace.</param>
        public override void WriteStartAttribute(string prefix, string localName, string ns)
        {
            // STEP 1 - Omits XSD and XSI declarations. 
            // From Kzu - http://weblogs.asp.net/cazzu/archive/2004/01/23/62141.aspx
            if (prefix == "xmlns" && (localName == "xsd" || localName == "xsi"))
            {
                _skip = true;
                return;
            }
            base.WriteStartAttribute(prefix, localName, ns);
        }

        /// <summary>
        /// Writes the string.
        /// </summary>
        /// <param name="text">The text.</param>
        public override void WriteString(string text)
        {
            if (_skip) return;
            base.WriteString(text);
        }

        /// <summary>
        /// Writes the end attribute.
        /// </summary>
        public override void WriteEndAttribute()
        {
            if (_skip)
            {
                // Reset the flag, so we keep writing.
                _skip = false;
                return;
            }
            base.WriteEndAttribute();
        }

        /// <summary>
        /// Writes the start document tag.
        /// </summary>
        public override void WriteStartDocument()
        {
            // STEP 2: Do nothing so we omit the xml declaration.
        }

        #endregion
    }
}